package display3D.objet3D
{
	import Tools.Geometry;
	import Tools.MeshUtils;
	
	import alternativa.engine3d.core.Clipping;
	import alternativa.engine3d.core.Face;
	import alternativa.engine3d.core.MipMapping;
	import alternativa.engine3d.core.Object3D;
	import alternativa.engine3d.core.Object3DContainer;
	import alternativa.engine3d.core.Sorting;
	import alternativa.engine3d.core.Vertex;
	import alternativa.engine3d.materials.FillMaterial;
	import alternativa.engine3d.materials.TextureMaterial;
	import alternativa.engine3d.objects.Mesh;
	import alternativa.engine3d.primitives.Plane;
	
	import flash.display.BitmapData;
	import flash.utils.Dictionary;
	
	import mx.controls.Alert;
	import display3D.embed.Texture;
	

	/**
	 * Classe représentant un mur de notre salle 3D
	 * @author Arnaud
	 */
	public class Mur
	{
		/**
		 * Hauteur des mur
		 * @default 500
		 */
		public static var hauteur:int=500;
		private var _x1:*;
		private var _y1:*;
		private var _x2:*;
		private var _y2:*;
		private var _oeuvres:Dictionary;
		private var _portes:Dictionary;
		private var _objet3D:Vector.<Object3D>;

		public function Mur(x1:*, y1:*, x2:*, y2:*)
		{
			_x1=x1;
			_y1=y1;
			_x2=x2;
			_y2=y2;
			_objet3D = new Vector.<Object3D>;
		}

		/**
		 * Dessine le mur et tout ses objets sur la scene
		 * @param scene Conteneur de notre salle3D
		 */
		public function draw(scene:Object3DContainer):void
		{
			//Calcul des coordonnées de la porte
			var v:Array = Geometry.coordonneVecteur(this._x1,this._y1,this._x2,this._y2);
			var longueurMur:* = Geometry.distance(this._x1,this._y1,this._x2,this._y2);
			
			//Vecteur normalisé mur
			var vN:Array = new Array;
			vN[0] = v[0]/longueurMur;
			vN[1] = v[1]/longueurMur;
			
			//Vecteur contenant les coordonnées des segments de mur
			var vectSegMur:Vector.<Object> = new Vector.<Object>;
			var oldCoord:Array = new Array();
			oldCoord[0] = _x1;
			oldCoord[1] = _y1;
			oldCoord[2] = _x2;
			oldCoord[3] = _y2;
			vectSegMur.push(oldCoord);

			//Calcul des nouvelles coordonnées pour laisser la place aux portes
			for each (var porte:Porte in this._portes)
			{		
				//Calcul des coordonnees
				var point1:Array = new Array;
				var point2:Array = new Array;
				
				point1[0] = porte.x -(vN[0]*Porte.taillePorte/2);
				point1[1] = porte.y -(vN[1]*Porte.taillePorte/2);
				
				point2[0] = porte.x +(vN[0]*Porte.taillePorte/2);
				point2[1] = porte.y +(vN[1]*Porte.taillePorte/2);
				for (var i:int = 0;i<vectSegMur.length;i++)
				{	

					var tempCoord:Array = vectSegMur[i];
					var tempx1:* = tempCoord[0];
					var tempz1:* = tempCoord[1];
					var tempx2:* = tempCoord[2];
					var tempz2:* = tempCoord[3];
					
					//Test pour savoir dans quel segment se trouve notre porte
					if ((point1[0] >=tempx1 && point1[0]<=tempx2) || (point1[0] >=tempx2 && point1[0]<=tempx1))
					{
						if ((point1[1] >=tempz1 && point1[1]<=tempz2) || (point1[1] >=tempz2 && point1[1]<=tempz1))
						{
							//Ici la porte est contenu dans notre segment donc on decoupe le segment
							if (Geometry.distance(tempx1,tempz1,point1[0],point1[1])<=Geometry.distance(tempx1,tempz1,point2[0],point2[1]))
							{
								//Premier nouveau segment
								var newSeg1:Array = new Array();
								newSeg1[0] = tempx1;
								newSeg1[1] = tempz1;
								newSeg1[2] = point1[0];
								newSeg1[3] = point1[1];

								//Second nouveau segment
								var newSeg2:Array = new Array();
								newSeg2[0] = tempx2;
								newSeg2[1] = tempz2;
								newSeg2[2] = point2[0];
								newSeg2[3] = point2[1];
							}
							else
							{
								//Premier nouveau segment
								var newSeg1:Array = new Array();
								newSeg1[0] = tempx1;
								newSeg1[1] = tempz1;
								newSeg1[2] = point2[0];
								newSeg1[3] = point2[1];

								//Second nouveau segment
								var newSeg2:Array = new Array();
								newSeg2[0] = tempx2;
								newSeg2[1] = tempz2;
								newSeg2[2] = point1[0];
								newSeg2[3] = point1[1];
							}

							//On supprime l'ancien segment du vecteur et on rajoute les deux nouveaux
							vectSegMur[i]=newSeg1;
							vectSegMur.push(newSeg2);
							break;
						}
					}
				}
			}

			var texture:TextureMaterial = new TextureMaterial(new (display3D.embed.Texture.EmbedTextureMur)().bitmapData, false, true, MipMapping.PER_PIXEL);
			texture.correctUV =true;
			
			//Maintenant on trace tout les segment de mur
			for (var i:int = 0;i<vectSegMur.length;i++)
			{
				
				//Calcul des murs
				var mesh:Mesh = new Mesh();
				var v1:Vertex = mesh.addVertex(vectSegMur[i][0], vectSegMur[i][1], Mur.hauteur, 0, 0, "v1");
				var v2:Vertex = mesh.addVertex(vectSegMur[i][0], vectSegMur[i][1], 0, 0, 1, "v2");
				var v3:Vertex = mesh.addVertex(vectSegMur[i][2], vectSegMur[i][3], 0, 1, 1, "v3");
				var v4:Vertex = mesh.addVertex(vectSegMur[i][2], vectSegMur[i][3],  Mur.hauteur, 1, 0, "v4");
				mesh.addFace(Vector.<Vertex>([v1, v2, v3, v4]), texture);
				mesh.addFace(Vector.<Vertex>([v4, v3, v2, v1]), texture);
				mesh.calculateFacesNormals(true);
				mesh.clipping = Clipping.FACE_CLIPPING;
				mesh.sorting = Sorting.DYNAMIC_BSP;
				mesh.calculateBounds();
				
				scene.addChild(mesh);
				_objet3D.push(mesh);
				
				var dist:* = Geometry.distance(vectSegMur[i][0],vectSegMur[i][1],vectSegMur[i][2],vectSegMur[i][3]);
				var v:Array = Geometry.coordonneVecteur(vectSegMur[i][0],vectSegMur[i][1],vectSegMur[i][2],vectSegMur[i][3]);
				var vN:Array = new Array;
				vN[0] = v[0]/dist;
				vN[1] = v[1]/dist;
				
			}

			//On dessine les porte
			for each (var porte:Porte in this._portes)
			{
				porte.draw(scene,this);
			}
			
			//On dessine les oeuvres
			for each (var oeuvre:Peinture in this._oeuvres)
			{
				oeuvre.draw(scene,this);
			}
			
			
		}
		
		/**
		 * Supprime le mur et tout ses objets de la scene
		 * @param scene Conteneur de notre salle3D
		 */
		public function supprimerMur(scene:Object3DContainer):void
		{
			for each (var objet:Object3D in _objet3D)
			{
				scene.removeChild(objet);
			}
			
			for each (var porte:Porte in this._portes)
			{
				porte.supprimerPorte(scene);
			}
			
			for each (var oeuvre:Peinture in this._oeuvres)
			{
				oeuvre.supprimerPeinture(scene);
			}
		}
		
		/**
		 * Effectue la translation de tout les point du mur et de ses objets par rapport au vecteur
		 * @param vecteur Vecteur de translation
		 */
		public function transformationVectoriel(vecteur:Array):void
		{
			this._x1 = this._x1 + vecteur[0];
			this._y1 = this._y1 + vecteur[1];
			this._x2 = this._x2 + vecteur[0];
			this._y2 = this._y2 + vecteur[1];
			
			for each (var porte:Porte in this._portes)
			{
				porte.x =porte.x + vecteur[0];
				porte.y =porte.y + vecteur[1];
			}
			
			for each (var oeuvre:Peinture in this._oeuvres)
			{
				oeuvre.x =oeuvre.x + vecteur[0];
				oeuvre.y =oeuvre.y + vecteur[1];
			}
			
		}
		
		/**
		 * Effectue une rotation de tout les point du mur ainsi que de ses objets
		 * @param pointRotation Point autour du quel s'effectue la rotation
		 * @param angle Anglede la rotation en radian
		 */
		public function transformationRotation(pointRotation:Array,angle:*):void
		{
			
			var tempX:* = this._x1;
			var tempZ:* = this._y1;
			this._x1 =  Math.cos(angle)*(tempX-pointRotation[0]) - Math.sin(angle)*(tempZ-pointRotation[1]) + pointRotation[0];
			this._y1 = Math.sin(angle)*(tempX-pointRotation[0]) + Math.cos(angle)*(tempZ-pointRotation[1]) + pointRotation[1];
			
			tempX = this._x2;
			tempZ = this._y2;
			
			this._x2 =  Math.cos(angle)*(tempX-pointRotation[0]) - Math.sin(angle)*(tempZ-pointRotation[1]) + pointRotation[0];
			this._y2 = Math.sin(angle)*(tempX-pointRotation[0]) + Math.cos(angle)*(tempZ-pointRotation[1]) + pointRotation[1];
			
			for each (var porte:Porte in this._portes)
			{
				tempX = porte.x;
				tempZ = porte.y;
				porte.x =  Math.cos(angle)*(tempX-pointRotation[0]) - Math.sin(angle)*(tempZ-pointRotation[1]) + pointRotation[0];
				porte.y = Math.sin(angle)*(tempX-pointRotation[0]) + Math.cos(angle)*(tempZ-pointRotation[1]) + pointRotation[1];
			}
			
			for each (var oeuvre:Peinture in this._oeuvres)
			{
				tempX = oeuvre.x;
				tempZ = oeuvre.y;
				oeuvre.x =  Math.cos(angle)*(tempX-pointRotation[0]) - Math.sin(angle)*(tempZ-pointRotation[1]) + pointRotation[0];
				oeuvre.y = Math.sin(angle)*(tempX-pointRotation[0]) + Math.cos(angle)*(tempZ-pointRotation[1]) + pointRotation[1];
			}
		}

		/**
		 * Coordonné x du point 1
		 */
		public function get x1():*
		{
			return _x1;
		}

		/**
		 * @private
		 */
		public function set x1(value:*):void
		{
			_x1 = value;
		}

		/**
		 * Coordonné y du point 1
		 */
		public function get y1():*
		{
			return _y1;
		}

		/**
		 * @private
		 */
		public function set y1(value:*):void
		{
			_y1 = value;
		}

		/**
		 * Coordonné x du point 2
		 */
		public function get x2():*
		{
			return _x2;
		}

		/**
		 * @private
		 */
		public function set x2(value:*):void
		{
			_x2 = value;
		}

		/**
		 * Coordonné y du point 2
		 */
		public function get y2():*
		{
			return _y2;
		}

		/**
		 * @private
		 */
		public function set y2(value:*):void
		{
			_y2 = value;
		}

		/**
		 *Portes présentes sur le mur
		 * @see Porte
		 */
		public function get portes():Dictionary
		{
			return _portes;
		}

		/**
		 * @private
		 */
		public function set portes(value:Dictionary):void
		{
			_portes = value;
		}

		/**
		 * Oeuvres présentes sur le mur
		 * @see Peinture
		 */
		public function get oeuvres():Dictionary
		{
			return _oeuvres;
		}

		/**
		 * @private
		 */
		public function set oeuvres(value:Dictionary):void
		{
			_oeuvres = value;
		}

		/**
		 * Contient tout les objets 3D du mur
		 */
		public function get objet3D():Vector.<Object3D>
		{
			return _objet3D;
		}

		/**
		 * @private
		 */
		public function set objet3D(value:Vector.<Object3D>):void
		{
			_objet3D = value;
		}


	}
}

